{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dGVterhZUeb7"
      },
      "source": [
        "\n",
        "\n",
        "# Multimodal RAG with Elasticsearch: The Gotham City Case\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JGuNiw7hUc6M"
      },
      "source": [
        "This notebook implements the Multimodal RAG (Retrieval-Augmented Generation) pipeline with Elasticsearch as described in the blog. We follow the same structure as the article, with each section explained and implemented in code.\n",
        "\n",
        "## Environment Setup\n",
        "\n",
        "First, we need to clone the repository that contains the complete project code."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UM5x0n2iA7o2"
      },
      "outputs": [],
      "source": [
        "!git clone https://github.com/elastic/elasticsearch-labs.git"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "U5k4YuR8TNZG"
      },
      "outputs": [],
      "source": [
        "import getpass"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "e6mW8JNyVdzi"
      },
      "source": [
        "Let's navigate to the project directory where the necessary files are located:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PHrDQc0jOOb7"
      },
      "outputs": [],
      "source": [
        "cd elasticsearch-labs/supporting-blog-content/building-multimodal-rag-with-elasticsearch-gotham"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LAGB159_Uaxb"
      },
      "source": [
        "Now let's configure the environment variables needed to connect to Elasticsearch and OpenAI. This is necessary for indexing and searching content, as well as generating the final report.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "U8IuJRQhS7lz"
      },
      "outputs": [],
      "source": [
        "ELASTICSEARCH_URL = input(\"Enter the Elasticsearch endpoint url: \")\n",
        "ELASTICSEARCH_API_KEY = getpass.getpass(\"Enter the Elasticsearch API key: \")\n",
        "OPENAI_API_KEY = getpass.getpass(\"Enter the OpenAI API key: \")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZC4v_SHjMwLa"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "\n",
        "os.environ[\"ELASTICSEARCH_API_KEY\"] = ELASTICSEARCH_API_KEY\n",
        "os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n",
        "os.environ[\"ELASTICSEARCH_URL\"] = ELASTICSEARCH_URL"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RNRExs7aVl45"
      },
      "source": [
        "\n",
        "## Installing Dependencies\n",
        "\n",
        "As mentioned in the blog, we need to install the specific dependencies, including the custom ImageBind fork:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FhPcJYl03eNL"
      },
      "outputs": [],
      "source": [
        "# Install base dependencies\n",
        "!pip install torch>=2.1.0 torchvision>=0.16.0 torchaudio>=2.1.0\n",
        "!pip install opencv-python-headless pillow numpy\n",
        "\n",
        "# Install the specific ImageBind fork\n",
        "!pip install git+https://github.com/hkchengrex/ImageBind.git"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LISqDRmE8PpG"
      },
      "outputs": [],
      "source": [
        "!pip -q install elasticsearch"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GGIFHatG9BTP"
      },
      "outputs": [],
      "source": [
        "!pip install python-dotenv"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "05Sq2ZtHTNZH"
      },
      "outputs": [],
      "source": [
        "!pip install openai"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LtJvz5t4TNZH"
      },
      "outputs": [],
      "source": [
        "!pip install soundfile"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jJt01mAeYaOT"
      },
      "source": [
        "## Stage 1 - Collecting Crime Scene Clues\n",
        "\n",
        "As explained in the blog, the first step is to verify that we have the correct directory structure and that the evidence files are present. We use `files_check.py` for this."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rZJexfwR4FaT"
      },
      "outputs": [],
      "source": [
        "!python stages/01-stage/files_check.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0a1tNsiGYjEZ"
      },
      "source": [
        "## Stage 2 - Generating Embeddings with ImageBind\n",
        "\n",
        "Now we test the embedding generation for an image using ImageBind. As the blog explains, ImageBind allows us to generate embeddings for different modalities (image, audio, text) in a shared vector space.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "A6C9IIuA6dlH"
      },
      "outputs": [],
      "source": [
        "!python stages/02-stage/test_embedding_generation.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Vw5xlFXgYls4"
      },
      "source": [
        "This script generates a 1024-dimensional embedding for a test image, confirming that the ImageBind model is working correctly.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Q2dsScL5ZF0X"
      },
      "source": [
        "\n",
        "## Stage 3 - Storage and Search in Elasticsearch\n",
        "\n",
        "### Content Indexing\n",
        "\n",
        "The next step is to index all multimodal evidence in Elasticsearch. This includes images, audio, text, and depth maps as described in the blog."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3nBsEf7u60bq"
      },
      "outputs": [],
      "source": [
        "!python stages/03-stage/index_all_modalities.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tf-8U-CGZXxW"
      },
      "source": [
        "\n",
        "Each piece of evidence is now indexed in Elasticsearch with their respective embeddings, allowing for similarity search.\n",
        "\n",
        "### Searching by Similarity Across Different Modalities\n",
        "\n",
        "Now we can test searching for evidence by similarity using different modalities as queries. The blog describes how an input from one modality can retrieve results from all modalities.\n",
        "\n",
        "#### Search by Audio\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7f-MBkFALphP"
      },
      "outputs": [],
      "source": [
        "!python stages/03-stage/search_by_audio.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nrGUO1JVZZnz"
      },
      "source": [
        "\n",
        "This command uses an audio file as a query and retrieves the most similar evidence. In the case of Gotham, this helps identify connections between the audio of a sinister laugh and other evidence.\n",
        "\n",
        "#### Search by Text"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "mm_RwbfYQBGK"
      },
      "outputs": [],
      "source": [
        "!python stages/03-stage/search_by_text.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YXhvE2EbZgQt"
      },
      "source": [
        "\n",
        "Here we use a text query (\"Why so serious?\") to find related evidence.\n",
        "\n",
        "#### Search by Image\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jrOBYZwtQQng"
      },
      "outputs": [],
      "source": [
        "!python stages/03-stage/search_by_image.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V2Ut2whVZm3s"
      },
      "source": [
        "This script uses an image from the crime scene to find similar visual evidence.\n",
        "\n",
        "#### Search by Depth Map\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Bbm1vWfXQiPZ"
      },
      "outputs": [],
      "source": [
        "!python stages/03-stage/search_by_depth.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DWSzg742ZoQw"
      },
      "source": [
        "As explained in the blog, depth maps can provide information about the 3D structure of the scene or objects, complementing the other modalities.\n",
        "\n",
        "## Stage 4 - Evidence Analysis with LLM\n",
        "\n",
        "Finally, we bring together all the retrieved evidence and use an LLM (GPT-4) to generate a forensic report that identifies the suspect based on the connections between the different modalities.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "A8pmOH31Q2Hc"
      },
      "outputs": [],
      "source": [
        "!python stages/04-stage/rag_crime_analyze.py"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VaWriUfjZyUz"
      },
      "source": [
        "\n",
        "This is the final step of the Multimodal RAG pipeline, where the LLM analyzes the evidence retrieved from Elasticsearch and synthesizes it into a coherent report that identifies the Joker as the main suspect.\n",
        "\n",
        "## Conclusion\n",
        "\n",
        "We have thus completed the implementation of the complete Multimodal RAG pipeline with Elasticsearch, following all the steps described in the blog. This pipeline demonstrates how different types of media can be analyzed in an integrated way to provide richer insights and connections between evidence that would be difficult to identify manually.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ji3l3u-bTNZI"
      },
      "outputs": [],
      "source": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XAj2w5qVTNZI"
      },
      "source": []
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.1"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
